#!/usr/bin/env python
# -*- coding:utf-8 -*-

import collections

# 利用字典推导可以把一个装满元组的列表变成两个不同的字典.
# 字典推导的应用
"""
DIAL_CODES = [ # 承载成对数据的列表,可直接用在字典的构造方法中.
    (86,'China'),
    (91,'India'),
    (1,'United States'),
    (62,'Indonesia'),
    (55,'Brazil'),
    (92,'Pakistan'),
    (880,'Bangladesh'),
    (234,'Nigeria'),
    (7,'Russia'),
    (81,'Japan'),
]
country_code = {country: code for code,country in DIAL_CODES} # 国家名是键,区域码是值.
print(country_code)
# 用区域码作为键,国家名称转换为大写,并且过滤掉区域码大于或等于66的地区.
{code: country.upper() for country,code in country_code.items() if code < 66}
"""

# 从索引中获取单词出现的频率信息,并把它们写进对应的列表里.
"""创建一个从单词到其出现情况的映射"""
"""
import sys,re

WORD_RE = re.compile(r'\w+')

index = {}
with open(sys.argv[1],encoding='utf-8') as fp:
    for line_no,line in enumerate(fp,1):
        for match in WORD_RE.finditer(line):
            word = match.group()
            column_no = match.start()+1
            location = (line_no,column_no)
            occurrences = index.get(word,[])
            occurrences.append(location)
            index[word] = occurrences
            # 以字母顺序打印出结果.

for word in sorted(index,key=str.upper):
    print(word,index[word])              
"""


# StrKeyDict0在查询时把非字符串的键转换为字符串
"""
class StrKeyDict0(dict): # StrKeyDict0继承了dict

    def __missing__(self,key):
        if isinstance(key,str): #找不到的键本身就是字符串,那就抛出KeyError异常.
            raise KeyError(key)
        return self[str(key)] # 找不到的键不是字符串,就把它转换成字符串再进行查找.

    def get(self,key,default=None):
        try:
            return self[key] # get方法把查找工作用self[key]的形式委托给__getitem__,在宣布查找失败之前,还能通过__missing__再给某个键一个机会.
        except KeyError:
            return default # 抛出KeyError,说明__missing__失败了,于是返回default.

def __contains__(self,key):
    return key in self.keys() or str(key) in self.keys() # 先按照传入键的原本的值来查找,如果没找到,再用str方法把键转换成字符串再查找一次.
"""

'''
为什么isinstance(key,str)测试在上面的__missing__中是必需的.
如果没有这个测试,只要str(k)返回的是一个存在的键,那么__missing__方法没问题.
不管是字符串键还是非字符串键,它都能正常运行. 如果str(k)不是一个存在的键,代码就会无限递归.
因为__missing__的最后一行中的self[str(key)]会调用__getitem__,而这个str(key)又不存在,于是__missing__又会被调用.

为了保持一致性,k in d 这个操作会调用__contains__方法. 
'''




# 3.5 字典的变种
"""
collections.OrderedDict:
    这个类型在添加键的时候回保持顺序。
    OrderedDict的popitem方法默认删除并返回的是字典里的最后一个元素.

collections.ChainMap
    这个类型可容纳数个不同的映射对象,然后再进行键查找时,
    这些对象会被当做一个整体被逐个查找,直到键被找到为止.

collections.Counter
    这个映射类型会给键准备一个整数计数器,每次更新一个键时都会增加这个计数器.
    这个类型可用来给可散列表对象计数.
"""
# 利用Counter来计算单词中各个字母出现的次数
"""
ct = collections.Counter('abracadabra')
print(ct)
ct.update('aaaaazzz')
print(ct)
print(ct.most_common(2))
"""



# 3.6 子类化UserDict
# 添加,更新,查询操作, StrKeyDict都会把非字符串的键转换为字符串
"""
class StrKeyDict(collections.UserDict):
    
    def __missing__(self,key):
        if isinstance(key,str):
            raise KeyError(key)
        return self[str(key)]

    def __contains__(self,key):
        # 所有已经存储的键都是字符串.在self.data上查询.
        return str(key) in self.data 

    def __setitem__(self,key,item):
        # 把所有的键都转换成字符串.
        self.data[str(key)] = item
"""




# 3.7 不可变映射类型
# types模块中引入了一个封装类名叫MappingProxyType. 如果给这个类一个映射,它会返回一个只读的映射视图.
# 用MappingProxyType来获取字典的只读实例
"""
from types import MappingProxyType
d = {1:'A'}
d_proxy = MappingProxyType(d)
print(d_proxy)
print(d_proxy[1])
# d_proxy[2] = 'x'  # 通过d_proxy不能做任何修改.
d[2] = 'B'
print(d_proxy) # 对d所做的任何改动会反馈到d_proxy上.
print(d_proxy[2])
"""



# 3.8 集合论
# 集合的本质是许多唯一对象的聚集,集合用于去重.
"""
l = ['spam','spam','eggs','span']
print(set(l))
print(list(set(l)))
# 给定两个集合a和b,a|b返回合集,a&b交集,a-b 差集.
# needles(电子邮件地址集合)的元素在集合(haystack)里出现的次数
found = 0
for n in needles:
    if n in haystack:
        found += 1

# needles的元素在haystack里出现的次数,代码可用在任何可迭代对象上.
found = len(set(needles)& set(haystack))
"""




# 3.8.1 集合字面量
# 除了空集,集合的字符串表示形式是{...}的形式出现.
"""
s = {1}
print(type(s))
print(s)
print(s.pop())
print(s)

# 用dis.dis(反汇编函数)查看两个方法的字节码的不同
from dis import dis
print(dis('{1}')) # 检查{1}字面量背后的字节码.
print(dis('set([1])')) # set([1])的字节码.
"""


# 3.8.2 集合推导
# 新建一个Latin-1字符集合,该集合里的每个字符的Unicode名字里都有"SIGN"这个单词.
from unicodedata import name  # 导入name函数,用以获取字符的名字
# 把编码在32~255之间的字符的名字里有"SIGN"单词的挑出来,放到一个集合.
print({chr(i) for i in range(32,256) if 'SIGN' in name(chr(i),'')})






# 3.8.3 集合的操作

